package com.learn.security.modules.security.weixin;

import cn.hutool.core.util.StrUtil;
import com.learn.security.modules.security.SecurityConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 微信登录的鉴权过滤器，模仿 UsernamePasswordAuthenticationFilter 实现
 *
 * @author jitwxs
 * @since 2019/1/9 13:52
 */
@Slf4j
public class WeixinCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    /**
     * 是否仅 POST 方式
     */
    private boolean getOnly = true;

    public WeixinCodeAuthenticationFilter() {
        // 微信登录的请求 get 方式 /wx/redirect
        super(new AntPathRequestMatcher(SecurityConstants.WEIXIN_REDIRECT_PROCESSING_URL, "GET"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        log.info("微信登录filter");
        if (getOnly && !request.getMethod().equals("GET")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        String code = obtainCode(request);
        if (StrUtil.isBlank(code)) {
            log.info("登录失败,code为空");
            throw new AuthenticationServiceException("登录失败,code为空");
        }

        // 设置登录用户对象
        WeixinCodeAuthenticationToken authRequest = new WeixinCodeAuthenticationToken(code);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected String obtainCode(HttpServletRequest request) {
        return request.getParameter("code");
    }

    protected void setDetails(HttpServletRequest request, WeixinCodeAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    public void setGetOnly(boolean getOnly) {
        this.getOnly = getOnly;
    }
}
